/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.engine.api.resource;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bff.engine.api.exception.BffEngineException;
import com.inspur.edp.bff.engine.api.exception.ErrorCodes;
import com.inspur.edp.bff.spi.builtin.BffEntityResInfoImpl;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.condition.SortCondition;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;
import com.inspur.edp.commonmodel.engine.api.common.CMEngineUtil;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.collection.VMElementCollection;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import io.iec.edp.caf.common.JSONSerializer;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BffEngineEntityResourceInfo extends BffEntityResInfoImpl {

    private final GspViewObject obj;
    private final BffEngineModelResInfo modelResInfo;
    private final GspBizEntityObject beObject;

    /**
     * 视图对象某对象的运行时信息
     *
     * @param obj
     * @param modelResInfo
     * @param beObject
     */
    public BffEngineEntityResourceInfo(GspViewObject obj, BffEngineModelResInfo modelResInfo,
                                       GspBizEntityObject beObject) {
        super(obj.getCode(), obj.getI18nResourceInfoPrefix() + ".Name", modelResInfo, obj.getID(), obj.getName());
        this.obj = obj;
        this.modelResInfo = modelResInfo;
        this.beObject = beObject;
        initColumns1();
        initSorts();
        initChildInfos1(modelResInfo);
    }

    /**
     * 初始化排序条件
     */
    private void initSorts() {
        if (!StringUtils.hasLength(obj.getOrderbyCondition())) {
            return;
        }
        List<SortCondition> sorts;
        try {
            sorts = JSONSerializer.deserialize(obj.getOrderbyCondition(), List.class, SortCondition.class);
        } catch (Exception e) {
            String nodeName = this.obj.getBelongModel() == null ? "" : this.obj.getBelongModel().getName();
            throw new BffEngineException(e, ErrorCodes.GSP_BFF_ENGINE_0010, nodeName, obj.getName(), obj.getOrderbyCondition());
        }
        if (sorts != null && !sorts.isEmpty()) {
            // 获取字段labelId与数据查询结构的映射关系
            Map<String, String> elementMap = getElementMap();

            sorts.forEach(sort -> {
                String target = elementMap.get(sort.getSortField());
                if (!StringUtils.hasText(target)) {
                    String nodeName = this.obj.getBelongModel() == null ? "" : this.obj.getBelongModel().getName();
                    throw new BffEngineException(ErrorCodes.GSP_BFF_ENGINE_0001, nodeName, obj.getName(), sort.getSortField());
                } else {
                    sort.setSortField(target);
                }
            });
            setSorts(sorts);
        }
    }

    /**
     * 根据字段构造查询结构
     *
     * @return 字段映射
     */
    private Map<String, String> getElementMap() {
        VMElementCollection containElements = obj.getContainElements();
        if (containElements == null || containElements.isEmpty()) {
            return new HashMap<>();
        }

        Map<String, String> elementMap = new HashMap<>();
        for (IGspCommonField element : containElements) {
            // 将字段映射为查询结构，如：Element -> Element
            elementMap.put(element.getLabelID(), element.getLabelID());

            //对于UDT字段和关联字段 额外处理其UDT字段和带出字段
            if (element.getIsUdt()) {
                // 获取UDT元数据
                UnifiedDataTypeDef udtContent = CMEngineUtil.getMetadataContent(element.getUdtID());
                // 支持 多列的多值UDT、单值UDT、单值UDT关联带出
                if (udtContent instanceof ComplexDataTypeDef) {
                    // 多值UDT仅支持 存为多列， 将每列的labelID转换为查询结构，如：Element_UDTColumn1 -> Element.UDTColumn1
                    if (((ComplexDataTypeDef) udtContent).getDbInfo().getMappingType() == ColumnMapType.MultiColumns) {
                        for (IGspCommonField childElement : element.getChildElements()) {
                            if (childElement.getLabelID().startsWith(element.getLabelID() + "_")) {
                                elementMap.put(childElement.getLabelID(),
                                        childElement.getLabelID().replaceFirst(element.getLabelID() + "_",
                                                element.getLabelID() + "."));
                            }
                        }
                    }
                } else if (udtContent instanceof SimpleDataTypeDef) {
                    // 单值UDT支持 业务字段和关联带出两种形式, 单值UDT查询结构与字段名相同无需额外处理
                    if (element.getHasAssociation()) {
                        // 关联带出形式中，将带出字段转换为查询结构，如：Element_RefElementID -> Element.RefElementID
                        for (GspAssociation association : element.getChildAssociations()) {
                            for (IGspCommonField childElement : association.getRefElementCollection()) {
                                if (childElement.getLabelID().startsWith(element.getLabelID() + "_")) {
                                    elementMap.put(childElement.getLabelID(),
                                            childElement.getLabelID().replaceFirst(element.getLabelID() + "_",
                                                    element.getLabelID() + "."));
                                }
                            }
                        }
                    }
                }
            } else if (element.getHasAssociation()) {
                // 关联带出形式，将带出字段转换为查询结构，如：Element_RefElementID -> Element.Element_RefElementID
                for (GspAssociation association : element.getChildAssociations()) {
                    for (IGspCommonField refElement : association.getRefElementCollection()) {
                        elementMap.put(refElement.getLabelID(), element.getLabelID() + "." + refElement.getLabelID());
                    }
                }
            }
        }
        return elementMap;
    }

    /**
     * 是否主对象
     *
     * @return
     */
    @Override
    public boolean isRoot() {
        return obj.isRootNode();
    }

    /**
     * 初始化列信息
     */
    protected void initColumns1() {
        super.initColumns();
        for (IGspCommonField field : obj.getContainElements()) {
            if (field.getObjectType() == GspElementObjectType.Association &&
                    (field.getChildAssociations() == null || field.getChildAssociations().isEmpty())) {
                continue;
            }
            GspViewModelElement voElement = (GspViewModelElement) field;
            if (field.getIsVirtual() || beObject == null) {
                addPropertyInfo(new BffEnginePropInfoGenerator().getDataTypePropertyInfo(voElement, null));
                continue;
            }
            IGspCommonElement beField = beObject.findElement(voElement.getMapping().getTargetElementId());
            addPropertyInfo(new BffEnginePropInfoGenerator().getDataTypePropertyInfo(voElement, beField == null ? null : (GspBizEntityElement) beField));
        }
    }

    /**
     * 返回视图对象的configId信息
     *
     * @return 视图对象configId
     */
    @Override
    public String getConfigId() {
        return obj.getBelongModel().getGeneratedConfigID();
    }

    /**
     * 获取子级信息
     *
     * @param modelResInfo
     */
    protected void initChildInfos1(CefModelResInfoImpl modelResInfo) {
        if (obj.getContainChildObjects() == null || obj.getContainChildObjects().isEmpty())
            return;
        for (IGspCommonObject childObj : obj.getContainChildObjects()) {
            addChildEntityResInfo(new BffEngineEntityResourceInfo((GspViewObject) childObj,
                    (BffEngineModelResInfo) modelResInfo, findChildBeObject((GspViewObject) childObj)));
        }
    }

    private GspBizEntityObject findChildBeObject(GspViewObject childObj) {
        if (beObject == null)
            return null;
        if (childObj.getIsVirtual())
            return null;
        return (GspBizEntityObject) beObject.getChildObjectById(childObj.getMapping().getTargetObjId());
    }

    public GspViewObject getViewObject() {
        return this.obj;
    }


    /**
     * 获取当前视图对象对应的实体对象，供运行时定制使用
     * @return 当前视图对象对应的实体对象
     */
    public GspBizEntityObject getBizEntityObject() {
        return this.beObject;
    }
}
